-------------------------------------------------------------------------------
--	 File name: init.lua
--		Author: Sploder
-- 		  Date: 03/01/2010
-- Description: This file contains the main body of code used by Sakuya's
--					normal (RED) knives.
--
-------------------------------------------------------------------------------

AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")

include('shared.lua')

-------------------------------------------------------------------------------
--	  Function: ENT:PhysicsUpdate()
-- Description: This function is called when we need to update the physics of
--					the entity.
-------------------------------------------------------------------------------
function ENT:PhysicsUpdate()
	if (SERVER)
	then
		-- If the velocity is greater than zero, set the entity's angles to be in the direction of the velocity.
		if (self:GetPhysicsObject():GetVelocity():LengthSqr() != 0)
		then
			self:SetLocalAngles(self:GetPhysicsObject():GetVelocity():GetNormalized():Angle())
		end
	end
end

-------------------------------------------------------------------------------
--	  Function: ENT:OnTakeDamage()
-- Description: This function is called when the entity takes damage.
-------------------------------------------------------------------------------
function ENT:OnTakeDamage()
	-- If the knife is still "alive," kill it.
	if (!self.dead)
	then
		self:SetMoveType(MOVETYPE_NONE)
		self.dead = true
		timer.Simple(0, self.Explode, self)
	end
end

-------------------------------------------------------------------------------
--	  Function: ENT:PhysicsCollide(data, physobj)
-- Description: This function is called when the entity collides with
--					something.
-------------------------------------------------------------------------------
function ENT:PhysicsCollide(data, physobj)
	-- If the knife is still alive, determine whether we should bounce or not.
	if (!self.dead)
	then
		-- If we still have bounces left, bounce.
		if (self.bounces < self.bouncesMax)
		then
			-- Make noise.
			WorldSound("sakuya/knifeBounce.wav", self:GetPos(), 75, 100)
		
			-- Find the reflection of the old velocity off of the hit normal
			local number = -2 * data.OurOldVelocity:Dot(data.HitNormal)
			local NewVelocity = data.HitNormal * number
			NewVelocity = data.OurOldVelocity + NewVelocity
			-- Reset the new velocity's speed to be the same as it was before the collision.
			NewVelocity:Normalize()
			NewVelocity = NewVelocity * data.OurOldVelocity:Length()
			-- Set the knife's new velocity.
			physobj:SetVelocity(NewVelocity)
			
			-- Increment the number of bounces.
			self.bounces = self.bounces + 1
			
		-- Otherwise, kill the knife.
		else
			self:SetMoveType(MOVETYPE_NONE)
			self.dead = true
			timer.Simple(0, self.Explode, self)
		end
	end
end

-------------------------------------------------------------------------------
--	  Function: ENT:StartTouch()
-- Description: This function is called when something first touches the
--					entity.
-------------------------------------------------------------------------------
function ENT:StartTouch()
end

-------------------------------------------------------------------------------
--	  Function: ENT:EndTouch()
-- Description: This function is called when something stops touching the
--					entity.
-------------------------------------------------------------------------------
function ENT:EndTouch()
end

-------------------------------------------------------------------------------
--	  Function: ENT:Touch(hitent)
-- Description: This function is called when something is touching the entity.
-------------------------------------------------------------------------------
function ENT:Touch(hitent)
	-- If the thing touching this entity is not the owner and is a player or NPC, and this entity isn't dead yet... *whew*
	if (hitent != self.Owner && !self.dead && (hitent:IsNPC() || hitent:IsPlayer()))
	then
		-- "Kill" the knife, but also do damage to the hit entity.
		self:SetMoveType(MOVETYPE_NONE)
		self:Explode(hitent)
	end
end

-------------------------------------------------------------------------------
--	  Function: ENT:Explode(hitent)
-- Description: This function is called to "kill" the knife entity, but it also
--					does damage.
-------------------------------------------------------------------------------
function ENT:Explode(hitent)
	-- Remove the knife entity.
	self:Remove()
	
	-- If the entity was not dead already, create an explosion effect.
	if (!self.dead)
	then
		-- If, somehow, we don't have an owner, set this entity's owner to itself.
		if (!self.Owner || !self.Owner:IsValid())
		then
			self.Owner = self
		end
		-- Make noise.
		WorldSound("sakuya/knifeHit01.wav", self:GetPos(), 100, 100)
		
		-- Make a hit effect.
		local edata = EffectData()
		edata:SetStart(self:GetPos())
		edata:SetOrigin(self:GetPos())
		edata:SetScale(1)
		util.Effect("sprite_knifeHit", edata)
		
		-- If the hit entity is valid, damage it!
		if (hitent && hitent:IsValid())
		then
			local dmg = DamageInfo()
			dmg:SetAttacker(self.Owner)
			dmg:SetInflictor(self)
			dmg:SetDamage(self.damage)
			dmg:SetDamageForce(vector_origin * 1)
			dmg:SetDamagePosition(self:GetPos())
			dmg:SetDamageType(DMG_GENERIC)
			hitent:TakeDamageInfo(dmg)
			
			-- Add some spiritpower.
			local pow = self.pPerHit
			-- If the hit entity died from this shot, add more spiritpower.
			if (hitent:IsNPC() && hitent:GetNPCState() == 7)
			then
				pow = pow + self.pPerKill
				-- Add a frag for it, too.
				self.Owner:AddFrags(1)
			end
			-- Add the power to the player.
			local weapon = self.Owner:GetWeapon("weapon_sakuya")
			if (weapon && weapon:IsValid())
			then
				weapon:AddPower(pow)
			end

		end
		
		self.dead = true	-- "Kill" the knife.
	end
end

-------------------------------------------------------------------------------
--	  Function: ENT:OnRemove()
-- Description: This function is called when the entity is removed.
-------------------------------------------------------------------------------
function ENT:OnRemove()
end

-------------------------------------------------------------------------------
--	  Function: ENT:Think()
-- Description: This function is called every step (or so) to do stuff...
-------------------------------------------------------------------------------
function ENT:Think()
	-- Set the next think to be the next frame.
	self:NextThink(CurTime())
	
	-- If the knife has been around past the kill timer, kill it.
	if (CurTime() > self.timer)
	then
			self:SetMoveType(MOVETYPE_NONE)
			self.dead = true
			timer.Simple(0, self.Explode, self)
	end

	return true
end

-------------------------------------------------------------------------------
--	  Function: GravGunOnPickedUp Hook
-- Description: This function is called when a player picks up this entity with
--					the gravgun.
-------------------------------------------------------------------------------
hook.Add("GravGunOnPickedUp", "GravGunOnPickedUpKnivesHook",
	function(pl, ent)
		-- If the entity picked up is a blueKnife, set the entity's owner to be the player who picked it up.
		if (ent:GetClass() == "sent_proj_sakuyaknife01")
		then
			ent:SetOwner(pl)
			ent.Owner = pl
		end
	end
)

-------------------------------------------------------------------------------
--	  Function: ShouldCollide Hook
-- Descrption: This function determines if various entities can collide or not.
-------------------------------------------------------------------------------
hook.Add("ShouldCollide", "ShouldCollideKnivesHook",
	function(ent1, ent2)
		-- If both entities are knives, but they have different owners, don't collide.
		if (ent1:GetClass() == "sent_proj_sakuyaknife01" && ent2:GetClass() == "sent_proj_sakuyaknife01")
		then
			--if (ent1.Owner != ent2.Owner)
			--then
				return false
			--end
		-- If one entity is a player and the other is a knife, and the player is the knife's owner, don't collide.
		elseif ((ent1:IsPlayer() && (ent2:GetClass() == "sent_proj_sakuyaknife01")) || (ent2:IsPlayer() && (ent1:GetClass() == "sent_proj_sakuyaknife01")))
		then
			if ((ent1 == ent2.Owner) || (ent2 == ent1.Owner))
			then
				return false
			end
		end
	end
)